curl --request POST \
--url https://cool.jobmojito.com/functions/v1/persona-create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "Difficult customer role-play",
"interview_template_id": "baa3bf7c-6926-46fd-9005-16738a31f72d",
"mojito_language_code": "en",
"status": "active",
"visibility": "merchant_public",
"persona_role_avatar": "is to act as a happy customer responding to questions",
"persona_role_user": "is to be a sales person trying to sell an additional product to the customer",
"description": "A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.",
"persona_avatar_who_is": "<string>",
"persona_avatar_knowledge": "<string>",
"persona_avatar_end_conditions": "<string>",
"persona_avatar_progress": "Mode: turning point\nInitial hold: ...\nUnlocks when: ...\nAfter unlock: ...\nHard limits: ...\nNo goalposts: ...\nGates: ...",
"opening_line": "Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?",
"candidate_expectations": "<string>",
"recording": "video_all",
"recording_full_session": "video_all",
"result_view": "full",
"interview_conversation_speed": "normal",
"candidate_video_introduction": "optional",
"max_duration": 1200,
"code": "my code",
"cover_image_url": "https://example.com/cover.png",
"interview_location": "remote",
"merchant_id": "28106cba-1c27-4e53-b149-32113e5e8e31",
"recruiter_profile_id": "<string>",
"welcome_message": "Welcome! You are about to speak with a customer who is unhappy about a recent price increase.",
"thank_you_message": "Thanks — your role-play has been recorded and will be reviewed by the hiring team.",
"tags": [
"interview-practice",
"sales"
],
"portal": "interview",
"interview_attempts": 3,
"is_embedded": false
}
EOFimport requests
url = "https://cool.jobmojito.com/functions/v1/persona-create"
payload = {
"name": "Difficult customer role-play",
"interview_template_id": "baa3bf7c-6926-46fd-9005-16738a31f72d",
"mojito_language_code": "en",
"status": "active",
"visibility": "merchant_public",
"persona_role_avatar": "is to act as a happy customer responding to questions",
"persona_role_user": "is to be a sales person trying to sell an additional product to the customer",
"description": "A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.",
"persona_avatar_who_is": "<string>",
"persona_avatar_knowledge": "<string>",
"persona_avatar_end_conditions": "<string>",
"persona_avatar_progress": "Mode: turning point
Initial hold: ...
Unlocks when: ...
After unlock: ...
Hard limits: ...
No goalposts: ...
Gates: ...",
"opening_line": "Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?",
"candidate_expectations": "<string>",
"recording": "video_all",
"recording_full_session": "video_all",
"result_view": "full",
"interview_conversation_speed": "normal",
"candidate_video_introduction": "optional",
"max_duration": 1200,
"code": "my code",
"cover_image_url": "https://example.com/cover.png",
"interview_location": "remote",
"merchant_id": "28106cba-1c27-4e53-b149-32113e5e8e31",
"recruiter_profile_id": "<string>",
"welcome_message": "Welcome! You are about to speak with a customer who is unhappy about a recent price increase.",
"thank_you_message": "Thanks — your role-play has been recorded and will be reviewed by the hiring team.",
"tags": ["interview-practice", "sales"],
"portal": "interview",
"interview_attempts": 3,
"is_embedded": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Difficult customer role-play',
interview_template_id: 'baa3bf7c-6926-46fd-9005-16738a31f72d',
mojito_language_code: 'en',
status: 'active',
visibility: 'merchant_public',
persona_role_avatar: 'is to act as a happy customer responding to questions',
persona_role_user: 'is to be a sales person trying to sell an additional product to the customer',
description: 'A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.',
persona_avatar_who_is: '<string>',
persona_avatar_knowledge: '<string>',
persona_avatar_end_conditions: '<string>',
persona_avatar_progress: 'Mode: turning point\nInitial hold: ...\nUnlocks when: ...\nAfter unlock: ...\nHard limits: ...\nNo goalposts: ...\nGates: ...',
opening_line: 'Oh, finally — someone actually comes over! I\'ve been waiting for ages. Are you going to help me or not?',
candidate_expectations: '<string>',
recording: 'video_all',
recording_full_session: 'video_all',
result_view: 'full',
interview_conversation_speed: 'normal',
candidate_video_introduction: 'optional',
max_duration: 1200,
code: 'my code',
cover_image_url: 'https://example.com/cover.png',
interview_location: 'remote',
merchant_id: '28106cba-1c27-4e53-b149-32113e5e8e31',
recruiter_profile_id: '<string>',
welcome_message: 'Welcome! You are about to speak with a customer who is unhappy about a recent price increase.',
thank_you_message: 'Thanks — your role-play has been recorded and will be reviewed by the hiring team.',
tags: ['interview-practice', 'sales'],
portal: 'interview',
interview_attempts: 3,
is_embedded: false
})
};
fetch('https://cool.jobmojito.com/functions/v1/persona-create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cool.jobmojito.com/functions/v1/persona-create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Difficult customer role-play',
'interview_template_id' => 'baa3bf7c-6926-46fd-9005-16738a31f72d',
'mojito_language_code' => 'en',
'status' => 'active',
'visibility' => 'merchant_public',
'persona_role_avatar' => 'is to act as a happy customer responding to questions',
'persona_role_user' => 'is to be a sales person trying to sell an additional product to the customer',
'description' => 'A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.',
'persona_avatar_who_is' => '<string>',
'persona_avatar_knowledge' => '<string>',
'persona_avatar_end_conditions' => '<string>',
'persona_avatar_progress' => 'Mode: turning point
Initial hold: ...
Unlocks when: ...
After unlock: ...
Hard limits: ...
No goalposts: ...
Gates: ...',
'opening_line' => 'Oh, finally — someone actually comes over! I\'ve been waiting for ages. Are you going to help me or not?',
'candidate_expectations' => '<string>',
'recording' => 'video_all',
'recording_full_session' => 'video_all',
'result_view' => 'full',
'interview_conversation_speed' => 'normal',
'candidate_video_introduction' => 'optional',
'max_duration' => 1200,
'code' => 'my code',
'cover_image_url' => 'https://example.com/cover.png',
'interview_location' => 'remote',
'merchant_id' => '28106cba-1c27-4e53-b149-32113e5e8e31',
'recruiter_profile_id' => '<string>',
'welcome_message' => 'Welcome! You are about to speak with a customer who is unhappy about a recent price increase.',
'thank_you_message' => 'Thanks — your role-play has been recorded and will be reviewed by the hiring team.',
'tags' => [
'interview-practice',
'sales'
],
'portal' => 'interview',
'interview_attempts' => 3,
'is_embedded' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://cool.jobmojito.com/functions/v1/persona-create"
payload := strings.NewReader("{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://cool.jobmojito.com/functions/v1/persona-create")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://cool.jobmojito.com/functions/v1/persona-create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}"
response = http.request(request)
puts response.read_body{
"interview_def_set_id": "00000000-0000-0000-0000-000000000000",
"embed_id": "<string>",
"embed_signing_key": "<string>"
}{
"error": "Field is required.",
"name": "interview_result_id"
}{
"error": "Field is required.",
"name": "interview_result_id"
}{
"error": "Field is required.",
"name": "interview_result_id"
}Create a role-play — coaching persona or interview-portal role-play (choose with `portal`)
FIRST DECIDE portal. This endpoint creates two different products and the default is NOT the recruiter one:
portal: "interview"— an INTERVIEW ROLE-PLAY. Use this whenever the goal is to ASSESS or SCREEN candidates: hiring, assessments, sales role-plays for job applicants, anything a recruiter runs. Candidates are invited through the normal invitation flow, results appear in the recruiter’s result list, it is billed against merchant credits, and attempts are capped viainterview_attempts— exactly like an interview.portal: "coaching"(THE DEFAULT) — a coaching persona for practice/training on the coaching portal. Consumed against the mentee’s own coaching credits, self-started from the catalogue, and its results are NOT visible to recruiters. Omittingportalgives you this one, so passportal: "interview"explicitly for any recruiting/assessment use case. The conversation itself behaves identically in both.
The avatar plays a defined role in a free-form conversation instead of running a scored Q&A interview. No AI question/description generation runs; the persona role fields ARE the configuration. The session runs as: a welcome message → the avatar’s OPENING LINE (the first thing it says, set via opening_line) → the candidate replies and the free-form role-play begins → a closing message. Because there is no question list, opening_line is how the avatar starts the scene — set it to a concrete in-character line; if omitted it defaults to a generic “Hello”. Set welcome_message and thank_you_message too — omitting them leaves the generic platform defaults. Also set candidate_expectations: it is the yardstick the session is scored against. The four avatar prompts divide up as: persona_avatar_who_is (identity and what drives it), persona_avatar_knowledge (the private facts it may use), persona_avatar_progress (how the conversation is allowed to move forward, and what gates the later personal details), and persona_avatar_end_conditions (when to stop). Without persona_avatar_progress the avatar has no defined arc and tends to either concede immediately or never concede at all. Provisions the default conversational steps and optionally an embed key.
curl --request POST \
--url https://cool.jobmojito.com/functions/v1/persona-create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "Difficult customer role-play",
"interview_template_id": "baa3bf7c-6926-46fd-9005-16738a31f72d",
"mojito_language_code": "en",
"status": "active",
"visibility": "merchant_public",
"persona_role_avatar": "is to act as a happy customer responding to questions",
"persona_role_user": "is to be a sales person trying to sell an additional product to the customer",
"description": "A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.",
"persona_avatar_who_is": "<string>",
"persona_avatar_knowledge": "<string>",
"persona_avatar_end_conditions": "<string>",
"persona_avatar_progress": "Mode: turning point\nInitial hold: ...\nUnlocks when: ...\nAfter unlock: ...\nHard limits: ...\nNo goalposts: ...\nGates: ...",
"opening_line": "Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?",
"candidate_expectations": "<string>",
"recording": "video_all",
"recording_full_session": "video_all",
"result_view": "full",
"interview_conversation_speed": "normal",
"candidate_video_introduction": "optional",
"max_duration": 1200,
"code": "my code",
"cover_image_url": "https://example.com/cover.png",
"interview_location": "remote",
"merchant_id": "28106cba-1c27-4e53-b149-32113e5e8e31",
"recruiter_profile_id": "<string>",
"welcome_message": "Welcome! You are about to speak with a customer who is unhappy about a recent price increase.",
"thank_you_message": "Thanks — your role-play has been recorded and will be reviewed by the hiring team.",
"tags": [
"interview-practice",
"sales"
],
"portal": "interview",
"interview_attempts": 3,
"is_embedded": false
}
EOFimport requests
url = "https://cool.jobmojito.com/functions/v1/persona-create"
payload = {
"name": "Difficult customer role-play",
"interview_template_id": "baa3bf7c-6926-46fd-9005-16738a31f72d",
"mojito_language_code": "en",
"status": "active",
"visibility": "merchant_public",
"persona_role_avatar": "is to act as a happy customer responding to questions",
"persona_role_user": "is to be a sales person trying to sell an additional product to the customer",
"description": "A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.",
"persona_avatar_who_is": "<string>",
"persona_avatar_knowledge": "<string>",
"persona_avatar_end_conditions": "<string>",
"persona_avatar_progress": "Mode: turning point
Initial hold: ...
Unlocks when: ...
After unlock: ...
Hard limits: ...
No goalposts: ...
Gates: ...",
"opening_line": "Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?",
"candidate_expectations": "<string>",
"recording": "video_all",
"recording_full_session": "video_all",
"result_view": "full",
"interview_conversation_speed": "normal",
"candidate_video_introduction": "optional",
"max_duration": 1200,
"code": "my code",
"cover_image_url": "https://example.com/cover.png",
"interview_location": "remote",
"merchant_id": "28106cba-1c27-4e53-b149-32113e5e8e31",
"recruiter_profile_id": "<string>",
"welcome_message": "Welcome! You are about to speak with a customer who is unhappy about a recent price increase.",
"thank_you_message": "Thanks — your role-play has been recorded and will be reviewed by the hiring team.",
"tags": ["interview-practice", "sales"],
"portal": "interview",
"interview_attempts": 3,
"is_embedded": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Difficult customer role-play',
interview_template_id: 'baa3bf7c-6926-46fd-9005-16738a31f72d',
mojito_language_code: 'en',
status: 'active',
visibility: 'merchant_public',
persona_role_avatar: 'is to act as a happy customer responding to questions',
persona_role_user: 'is to be a sales person trying to sell an additional product to the customer',
description: 'A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.',
persona_avatar_who_is: '<string>',
persona_avatar_knowledge: '<string>',
persona_avatar_end_conditions: '<string>',
persona_avatar_progress: 'Mode: turning point\nInitial hold: ...\nUnlocks when: ...\nAfter unlock: ...\nHard limits: ...\nNo goalposts: ...\nGates: ...',
opening_line: 'Oh, finally — someone actually comes over! I\'ve been waiting for ages. Are you going to help me or not?',
candidate_expectations: '<string>',
recording: 'video_all',
recording_full_session: 'video_all',
result_view: 'full',
interview_conversation_speed: 'normal',
candidate_video_introduction: 'optional',
max_duration: 1200,
code: 'my code',
cover_image_url: 'https://example.com/cover.png',
interview_location: 'remote',
merchant_id: '28106cba-1c27-4e53-b149-32113e5e8e31',
recruiter_profile_id: '<string>',
welcome_message: 'Welcome! You are about to speak with a customer who is unhappy about a recent price increase.',
thank_you_message: 'Thanks — your role-play has been recorded and will be reviewed by the hiring team.',
tags: ['interview-practice', 'sales'],
portal: 'interview',
interview_attempts: 3,
is_embedded: false
})
};
fetch('https://cool.jobmojito.com/functions/v1/persona-create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cool.jobmojito.com/functions/v1/persona-create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Difficult customer role-play',
'interview_template_id' => 'baa3bf7c-6926-46fd-9005-16738a31f72d',
'mojito_language_code' => 'en',
'status' => 'active',
'visibility' => 'merchant_public',
'persona_role_avatar' => 'is to act as a happy customer responding to questions',
'persona_role_user' => 'is to be a sales person trying to sell an additional product to the customer',
'description' => 'A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.',
'persona_avatar_who_is' => '<string>',
'persona_avatar_knowledge' => '<string>',
'persona_avatar_end_conditions' => '<string>',
'persona_avatar_progress' => 'Mode: turning point
Initial hold: ...
Unlocks when: ...
After unlock: ...
Hard limits: ...
No goalposts: ...
Gates: ...',
'opening_line' => 'Oh, finally — someone actually comes over! I\'ve been waiting for ages. Are you going to help me or not?',
'candidate_expectations' => '<string>',
'recording' => 'video_all',
'recording_full_session' => 'video_all',
'result_view' => 'full',
'interview_conversation_speed' => 'normal',
'candidate_video_introduction' => 'optional',
'max_duration' => 1200,
'code' => 'my code',
'cover_image_url' => 'https://example.com/cover.png',
'interview_location' => 'remote',
'merchant_id' => '28106cba-1c27-4e53-b149-32113e5e8e31',
'recruiter_profile_id' => '<string>',
'welcome_message' => 'Welcome! You are about to speak with a customer who is unhappy about a recent price increase.',
'thank_you_message' => 'Thanks — your role-play has been recorded and will be reviewed by the hiring team.',
'tags' => [
'interview-practice',
'sales'
],
'portal' => 'interview',
'interview_attempts' => 3,
'is_embedded' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://cool.jobmojito.com/functions/v1/persona-create"
payload := strings.NewReader("{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://cool.jobmojito.com/functions/v1/persona-create")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://cool.jobmojito.com/functions/v1/persona-create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Difficult customer role-play\",\n \"interview_template_id\": \"baa3bf7c-6926-46fd-9005-16738a31f72d\",\n \"mojito_language_code\": \"en\",\n \"status\": \"active\",\n \"visibility\": \"merchant_public\",\n \"persona_role_avatar\": \"is to act as a happy customer responding to questions\",\n \"persona_role_user\": \"is to be a sales person trying to sell an additional product to the customer\",\n \"description\": \"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account.\",\n \"persona_avatar_who_is\": \"<string>\",\n \"persona_avatar_knowledge\": \"<string>\",\n \"persona_avatar_end_conditions\": \"<string>\",\n \"persona_avatar_progress\": \"Mode: turning point\\nInitial hold: ...\\nUnlocks when: ...\\nAfter unlock: ...\\nHard limits: ...\\nNo goalposts: ...\\nGates: ...\",\n \"opening_line\": \"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?\",\n \"candidate_expectations\": \"<string>\",\n \"recording\": \"video_all\",\n \"recording_full_session\": \"video_all\",\n \"result_view\": \"full\",\n \"interview_conversation_speed\": \"normal\",\n \"candidate_video_introduction\": \"optional\",\n \"max_duration\": 1200,\n \"code\": \"my code\",\n \"cover_image_url\": \"https://example.com/cover.png\",\n \"interview_location\": \"remote\",\n \"merchant_id\": \"28106cba-1c27-4e53-b149-32113e5e8e31\",\n \"recruiter_profile_id\": \"<string>\",\n \"welcome_message\": \"Welcome! You are about to speak with a customer who is unhappy about a recent price increase.\",\n \"thank_you_message\": \"Thanks — your role-play has been recorded and will be reviewed by the hiring team.\",\n \"tags\": [\n \"interview-practice\",\n \"sales\"\n ],\n \"portal\": \"interview\",\n \"interview_attempts\": 3,\n \"is_embedded\": false\n}"
response = http.request(request)
puts response.read_body{
"interview_def_set_id": "00000000-0000-0000-0000-000000000000",
"embed_id": "<string>",
"embed_signing_key": "<string>"
}{
"error": "Field is required.",
"name": "interview_result_id"
}{
"error": "Field is required.",
"name": "interview_result_id"
}{
"error": "Field is required.",
"name": "interview_result_id"
}Authorizations
Supabase JWT — Authorization: Bearer <token>.
Body
Persona / session name.
1"Difficult customer role-play"
Id of the interview template (avatar) the persona uses.
1"baa3bf7c-6926-46fd-9005-16738a31f72d"
Platform language code used for the conversation. Must be one of the platform-languages.json codes.
ar, bg, zh, hr, cs, da, nl, en, fil, fi, fr, de, el, hi, hu, id, it, ja, ko, ms, no, pl, pt, br, ro, ru, sk, es, sv, ta, th, tr, uk, vi "en"
Lifecycle status of the interview. Options — draft: Created but not published — not visible to candidates and cannot be run yet. Use to stage an interview before going live. | active: Published and live — candidates can run it..
draft, active "active"
Who can discover and access the interview. Options — merchant_public: Listed on the merchant's public interview list — anyone with the merchant link can find and start it. | merchant_invite: Invite-only — only candidates explicitly invited (by email/link) can access it; not listed anywhere. | merchant_unlisted: Reachable only via a direct link — not listed anywhere; share the link manually..
merchant_public, merchant_invite, merchant_unlisted "merchant_public"
The role the AI avatar plays. Candidate-visible — shown on the pre-session poster as 'Role of the agent', so write it as candidate-facing setup and keep it to max 2 sentences. Example: 'is to act as a happy customer responding to questions'.
1"is to act as a happy customer responding to questions"
The role the candidate (mentee) plays. Candidate-visible — shown on the pre-session poster as 'Your role', so write it as candidate-facing setup and keep it to max 2 sentences. Example: 'is to be a sales person trying to sell an additional product to the customer'.
1"is to be a sales person trying to sell an additional product to the customer"
Short persona description shown to the candidate on the pre-session poster. Candidate-visible — keep it to max 2 sentences. Unlike job-interview-create, personas run no AI generation, so this is never auto-generated: leave it null/blank and the poster simply shows no description; set it to frame the scene.
"A quick sales role-play with an unhappy customer. Your goal is to resolve their complaint and keep the account."
Who the avatar represents: name, role, context, personality, woven with what drives them underneath (motive, fear, what they refuse until heard, what they do not know until told). One continuous description; no labelled subsections.
Private facts the avatar can use (numbers, dates, names, objections), plus any personal details shareable only after progress and only if natural — timing written inline, not as labelled subsections. Those personal details are never required for the goal.
When the avatar should end the session. Prefer referring to persona_avatar_progress: wrap up when progress is complete (turning point unlocked and a plan accepted, or steps "Done when" reached), or when the conversation has clearly broken down.
How the conversation moves forward — one plain-text value starting with Mode: turning point (resistance) or Mode: steps (difficult conversation protocol), then the labelled lines for that mode (Initial hold / Unlocks when / … or Framework / Steps / …), including a Gates line: do not share later personal details from persona_avatar_knowledge until progress is earned.
"Mode: turning point\nInitial hold: ...\nUnlocks when: ...\nAfter unlock: ...\nHard limits: ...\nNo goalposts: ...\nGates: ..."
The avatar's opening line — the FIRST thing it says out loud when the session starts, before the candidate has said anything. This is a literal spoken line, NOT a description: write the exact words the avatar should say, in character and consistent with persona_role_avatar. For an escalated scenario it should already convey that state (e.g. an angry customer opens angrily). If omitted, the platform inserts a generic default ("Hello"), which is usually a weak opener — set this for anything other than a neutral greeting.
"Oh, finally — someone actually comes over! I've been waiting for ages. Are you going to help me or not?"
Mentee assessment goals — free-text describing what the candidate is expected to achieve (max 2100 chars).
2100Cheating/proctoring detection mode for candidate answers — this is NOT a full session recording. Video options also record the candidate. Omit/null to disable. Options — audio_first_5_answers: Audio-only cheating detection, first 5 answers only. | audio_all: Audio-only cheating detection on every answer. | video_all: Audio + video cheating detection on every answer (candidate is recorded for all answers). | video_first_5_answers: Audio + video cheating detection, first 5 answers only..
audio_first_5_answers, audio_all, video_all, video_first_5_answers "video_all"
Full interview-session recording (includes the avatar and voice) produced as a single file. Independent of recording. Omit/null to disable. Options — audio_all: Record the whole session audio (avatar + candidate voice) into a single file. Adds +0.2 credits. | video_all: Record the whole session video + audio (avatar + candidate) into a single file. Adds +0.4 credits..
audio_all, video_all "video_all"
Result screen shown to the candidate after finishing. With any value other than none, the candidate sees a results screen where they can provide feedback, record an intro video and edit the transcript, and must then submit the result; the value sets how much score/result detail is shown. Options — none: No results screen at all — the interview is submitted immediately when the candidate finishes (no feedback, intro video, transcript edit or manual submit step). | minimal: Minimal results layout, no score shown. | minimal_with_score: Minimal results layout including the overall score. | advanced: Advanced results layout with more detail. | full: Full results layout with all sections. | full_expand_scores: Full results with every score breakdown expanded..
none, minimal, minimal_with_score, advanced, full, full_expand_scores "full"
Conversation pace of the AI avatar. Omit/null keeps the template default pace. Options — slower: The avatar speaks more slowly — easier to follow for non-native speakers. | normal: Default speaking pace. | faster: The avatar speaks more quickly for a snappier conversation..
slower, normal, faster "normal"
Whether a candidate video introduction is optional or required.
optional, required "optional"
Maximum conversation duration in seconds. Defaults to 1200 (20 min) when omitted.
1200
Optional external code/reference for the persona.
"my code"
Cover image URL.
"https://example.com/cover.png"
Optional location label shown for the session.
"remote"
Merchant id. Admin / sub-merchant callers only; otherwise taken from your token.
"28106cba-1c27-4e53-b149-32113e5e8e31"
Profile id of the recruiter owning this persona. Must be a merchant/merchant_owner/admin profile of the same merchant.
Custom welcome message spoken to the candidate before the role-play starts — set it; omitting it leaves a generic platform default. This is the scene-setting message; the avatar's first in-character line is opening_line, which comes after it.
"Welcome! You are about to speak with a customer who is unhappy about a recent price increase."
Custom thank-you message shown after the session — set it; omitting it leaves a generic platform default.
"Thanks — your role-play has been recorded and will be reviewed by the hiring team."
Free-form tags stored on the persona. Tags are also the coaching-catalogue mapping key: a catalogue directory (see the catalogue-tag-create / catalogue-tag-update endpoints) lists a coaching or persona session when the session's tags contain EVERY tag in that directory's tags_interview_set_filter. Only active sessions with visibility public or merchant_public are listed.
["interview-practice", "sales"]
REQUIRED IN PRACTICE — pick deliberately; the default is the coaching product, not the recruiting one. interview: an interview role-play. Choose this for ANY recruiting or assessment use case (screening candidates, hiring, sales role-plays for applicants). Candidates are invited through the normal invitation flow, results are visible to the recruiter alongside ordinary interview results, it is billed against your merchant credits on the same basis as an interview, and attempts are capped (see interview_attempts). | coaching (DEFAULT when omitted): the classic coaching persona for practice/training. Runs on the coaching portal, is consumed against the mentee's own coaching credits, is started by the mentee from the catalogue or a shared link, and its results are NOT visible to recruiters. The conversation itself behaves identically in both cases — only the portal, billing, visibility and attempt limits differ.
coaching, interview "interview"
Allowed candidate attempts (1-20), defaulting to 3. Only meaningful when portal is interview; coaching personas are unlimited. A recruiter can still grant an extra attempt afterwards.
1 <= x <= 203
Set true when the persona will be embedded as an iframe on an external page. Provisions an embed key and returns embed_id / embed_signing_key.
false
Response
Persona created.
Id of the created persona. Includes embed_id/embed_signing_key when is_embedded=true.